import $ from 'jquery'
String.format = function() {
  var s = arguments[0]
  for (var i = 0; i < arguments.length - 1; i++) {
    var reg = new RegExp('\\{' + i + '\\}', 'gm')
    s = s.replace(reg, arguments[i + 1])
  }
  return s
}
function PrintDoc(debug) {
  this.point = { x: 0, y: 0 }
  this.renderEls = []
  this.printCmds = []
  this.height = 0
  this.width = 0
  this.debugger = false
  this.add = function(el) {
    if (!el.render) {
      console.log('未实现render接口')
      return
    }
    this.renderEls.push(el)
  }
  this.render = function() {
    for (var i in this.renderEls) {
      var el = this.renderEls[i]
      el.render()
    }
    return this
  }
  if (debug) {
    this.canvas = document.getElementById('panel')
    this.context = this.canvas.getContext('2d')
  }
  this.getCms = function() {
    // debugger;
    return {
      'cmd': 2,
      'printer': 'PDF',
      'count': 1,
      'startindex': 0,
      'elements': this.printCmds
    }
  }
}
class DocTable {
  borderSize = 1
  rds = []
  height = 0
  cls = {}
  font = {
    family: '微软雅黑',
    size: 10
  }
  marge = { left: 0, right: 0, top: 0 }
  cols = []
  constructor(doc, width, lineHeight, cols) {
    this.doc = doc
    this.point = doc.point
    this.lineHeight = lineHeight
    this.width = width
    this.cols = cols
    this.refreshCols()
    this.doc.add(this)
  }

  setMarge(marge) {
    if (marge.left) {
      this.marge.left = marge.left || 0
    }
    if (marge.top) {
      this.marge.top = marge.top || 0
    }
    if (marge.right) {
      this.marge.right = marge.right || 0
    }
    this.width = this.width - this.marge.left - this.marge.right
    this.refreshCols()
  }
  refreshCols() {
    const len = this.cols.length
    let totalWidth = 0
    for (let i = 0; i < len - 1; i++) {
      const col = this.cols[i]
      this.cls[i] = parseInt(this.width * col / 100)
      totalWidth += this.cls[i]
    }
    this.cls[len - 1] = this.width - totalWidth
  }

  addTR(tr) {
    this.rds.push(tr)
  }
  calc() {
    const _this = this
    for (var i = 0; i < _this.rds.length; i++) {
      var item = _this.rds[i]
      var j_len = item.tds.length
      for (var j = 0; j < j_len; j++) {
        var td = item.tds[j]
        if (td.rowspan > 1) {
          td.flag = td.flag ^ (td.flag & (1 << 0)) ^ (0 << 0)
          for (var m = 1; m < td.rowspan; m++) {
            var tr = _this.rds[i + m]
            const newtd = new DocTD(tr, j)
            if (m < td.rowspan - 1) {
              newtd.flag = newtd.flag ^ (newtd.flag & (1 << 0)) ^ (0 << 0)
            }
            if (td.colspan > 1) {
              newtd.flag = newtd.flag ^ (newtd.flag & (1 << 1)) ^ (0 << 1)
            }
          }
        }
        if (td.colspan > 1) {
          td.flag = td.flag ^ (td.flag & (1 << 1)) ^ (0 << 1)
          for (let m = 1; m < td.colspan; m++) {
            const newtd = new DocTD(item, j * 1 + m)
            j_len++
            if (m < td.colspan - 1) {
              newtd.flag = newtd.flag ^ (newtd.flag & (1 << 1)) ^ (0 << 1)
            }
            if (td.rowspan > 1) {
              newtd.flag = newtd.flag ^ (newtd.flag & (1 << 0)) ^ (0 << 0)
              for (var n = 1; n < td.rowspan; n++) {
                const tr = _this.rds[i + n]
                var newtd1 = new DocTD(tr, j * 1 + m)
                if (n < td.rowspan - 1) {
                  newtd1.flag = newtd1.flag ^ (newtd1.flag & (1 << 0)) ^ (0 << 0)
                }
                if (m < td.colspan - 1) {
                  newtd1.flag = newtd1.flag ^ (newtd1.flag & (1 << 1)) ^ (0 << 1)
                }
              }
            }
          }
        }
      }
    }
  }

  render() {
    this.calc()
    this.calcLen()
    this.calcUse()
    this.point.x += this.marge.left || 0
    this.point.y += this.marge.top || 0
    this.drawLine(this.point.x, this.point.y, this.point.x + this.width, this.point.y)
    this.drawLine(this.point.x, this.point.y, this.point.x, this.point.y + this.height)
    for (var i = 0; i < this.rds.length; i++) {
      var item = this.rds[i]
      item.render(this.cls)
    }
    this.point.x -= this.marge.left || 0
  }
  calcLen() {
    for (var i = 0; i < this.rds.length; i++) {
      var item = this.rds[i]
      item.calc()
    }
    var _this = this
    var reCalcLen = function() {
      for (var i = 0; i < _this.rds.length; i++) {
        var item = _this.rds[i]
        for (var j in item.tds) {
          var td = item.tds[j]
          if (td.rowspan <= 1 || td.h < item.h) {
            td.h = item.h
          }
        }
      }
    }
    reCalcLen()
    var reCount = 0
    var reCalc = function() {
      reCount++
      if (reCount > 10) {
        return
      }
      for (var i = 0; i < _this.rds.length; i++) {
        var item = _this.rds[i]
        for (var j in item.tds) {
          var td = item.tds[j]
          if (td.rowspan > 1 && td.h > item.h) {
            let totalLen = item.h
            for (var m = 1; m < td.rowspan; m++) {
              totalLen += _this.rds[i + m].h
            }
            if (totalLen < td.h) {
              var ttr = _this.rds[i + td.rowspan - 1]
              ttr.h += td.h - totalLen
              for (var n in ttr.tds) {
                if (ttr.tds[n].h < ttr.h) {
                  ttr.tds[n].h = ttr.h
                }
              }
            }
            td.h = item.h
            reCalc()
            return
          }
        }
      }
    }
    reCalc()
  }
  calcUse() {
    const _this = this
    let totalHeight = 0
    for (var i = 0; i < _this.rds.length; i++) {
      var item = _this.rds[i]
      totalHeight += item.h
      for (var j in item.tds) {
        var td = item.tds[j]
        td.useH = item.h
        if (td.rowspan > 1) {
          for (var m = 1; m < td.rowspan; m++) {
            var tr = _this.rds[i + m]
            td.useH += tr.h
          }
        }
      }
    }
    this.height = totalHeight
  }

  drawLine(x1, y1, x2, y2, bs) {
    const borderSize = bs || this.borderSize
    if (borderSize) {
      this.doc.printCmds.push({ 'etype': 2, 'size': borderSize, 'x': x1, 'y': y1, 'x1': x2, 'y1': y2 })
    }
    if (this.doc.debugger === false || borderSize === 0) {
      return
    }
    // var canvas = this.doc.canvas
    var context = this.doc.context
    context.strokeStyle = '#020001'
    context.lineWidth = 1
    context.moveTo(x1, y1)
    context.lineTo(x2, y2)
    context.stroke()
  }
  drawText(txt, x, y, font) {
    const fontSize = font.size || this.font.size
    this.doc.printCmds.push({ 'etype': 1, 'evalue': txt, 'size': fontSize, 'x': x, 'y': y })
    if (this.doc.debugger === false) {
      return
    }
    var canvas = this.doc.canvas
    if (!canvas || !canvas.getContext) {
      return false
    }
    var context = this.doc.context
    context.font = fontSize + "px '微软雅黑'"
    context.textBaseline = 'top'
    context.fillText(txt, x, y)
  }
  drawImg(url, x, y, tag) {
    if (!tag || !tag.style) {
      return
    }
    const dw = tag.style.width
    const dh = tag.style.height
    const x1 = x + dw
    const y1 = y + dh
    this.doc.printCmds.push({ 'etype': 4, 'vtype': 1, 'source': url, 'x': x, 'x1': x1, 'y': y, 'y1': y1 })
    if (this.doc.debugger === false) {
      return
    }
    const _this = this
    const img = new Image()
    img.onload = function() {
      _this.calcImage(img, dw, dh)
      // let x1=x+img.width;
      // let y1=y+img.height;
      // TODO...
      // _this.doc.printCmds.push({"etype":4,"vtype":1,"source":url,"x":x,"x1":x1,"y":y,"y1":y1});
      // if(_this.doc.debugger==false){
      //    return;
      // }
    }
    img.src = url
    var canvas = document.getElementById('panel')
    if (!canvas || !canvas.getContext) {
      return false
    }
    const ctx = canvas.getContext('2d')
    ctx.drawImage(img, x, y, img.width, img.height)
  }
  calcImage(ImgObj, maxWidth, maxHeight) {
    var image = new Image()
    // 原图片原始地址（用于获取原图片的真实宽高，当<img>标签指定了宽、高时不受影响）
    image.src = ImgObj.src
    // 用于设定图片的宽度和高度
    var tempWidth
    var tempHeight
    debugger
    if (image.width > 0 && image.height > 0) {
      // 原图片宽高比例 大于 指定的宽高比例，这就说明了原图片的宽度必然 > 高度
      if (image.width / image.height >= maxWidth / maxHeight) {
        if (image.width > maxWidth) {
          tempWidth = maxWidth
          // 按原图片的比例进行缩放
          tempHeight = (image.height * maxWidth) / image.width
        } else {
          // 按原图片的大小进行缩放
          tempWidth = image.width
          tempHeight = image.height
        }
      } else { // 原图片的高度必然 > 宽度
        if (image.height > maxHeight) {
          tempHeight = maxHeight
          // 按原图片的比例进行缩放
          tempWidth = (image.width * maxHeight) / image.height
        } else {
          // 按原图片的大小进行缩放
          tempWidth = image.width
          tempHeight = image.height
        }
      }
      // 设置页面图片的宽和高
      ImgObj.height = tempHeight
      ImgObj.width = tempWidth
      // 提示图片的原来大小
      ImgObj.alt = image.width + '×' + image.height
    }
  }
}
class DocTR {
  tds = []
  len = 1
  constructor(tb) {
    this.doctable = tb
    this.lineHeight = this.doctable.lineHeight || 10
    this.h = this.lineHeight
    if (tb) {
      tb.addTR(this)
    }
    this.point = this.doctable.point
  }
  setLineHeight(h) {
    this.h = h
    this.lineHeight = h
  }

  render(cls) {
    for (var i in this.tds) {
      var td = this.tds[i]
      td.render(cls[i])
    }
    this.point.x = this.doctable.marge.left || 0
    this.point.y += this.h
  }
  addTD(td, j) {
    if (typeof (j) !== 'undefined') {
      this.tds.splice(j, 0, td)
      return
    }
    this.tds.push(td)
  }
  calc(w) {
    var _this = this
    for (var i in _this.tds) {
      var td = _this.tds[i]
      let w = _this.doctable.cls[i]
      if (td.colspan > 1) {
        for (var j = 1; j < td.colspan; j++) {
          w += _this.doctable.cls[j + i * 1]
        }
      }
      td.calc(w)
    }
  }
}
class DocTD {
  len = 1
  rowspan = 1
  colspan = 1
  flag = 3
  useH = this.h
  useW = 0
  align = 0
  borderSize = 0
  constructor(tr, j) {
    if (!tr) {
      throw new Error('TR 缺失')
    }
    this.tr = tr
    this.lineHeight = this.tr.lineHeight
    this.h = this.lineHeight
    tr.addTD(this, j)
    this.point = this.tr.doctable.point
    this.font = this.tr.doctable.font
  }
  getNumCount(str) {
    const regex = /[0-9]|[\x00-\xff]/g
    const result = str.match(regex)
    return !result ? 2 : 1
  }
  setBorderLine(bl) {
    this.flag = bl
  }
  setBorderSize(bs) {
    this.borderSize = bs
  }
  calc(w) {
    this.useW = w
    if (!this.content) {
      return
    }
    const fontSize = this.tr.doctable.font.size
    const fw = Math.floor(w / fontSize)
    if (this.tag) {
      const tag = this.tag
      if (tag.name && tag.name === 'image') {
        this.h = tag.style.height
      }
    } else {
      this.contentArray = []
      const tmpArr = (this.content + '').split(/[(\r\n)\r\n]/)
      for (const i in tmpArr) {
        const tmpc = tmpArr[i]
        let lineLen = 0
        let charLen = 0
        for (let j = 0; j < tmpc.length; j++) {
          let c = tmpc[j]
          lineLen += this.getNumCount(c)
          charLen++
          if ((fw * 2) < lineLen) {
            j--
            charLen--
            c = tmpc[j]
            lineLen -= this.getNumCount(c)
            this.contentArray.push({ text: tmpc.substr(j - charLen + 1, charLen), len: lineLen })
            lineLen = 0
            charLen = 0
          }
        }
        if (lineLen > 0) {
          this.contentArray.push({ text: tmpc.substr(tmpc.length - charLen, charLen), len: lineLen })
        }
      }
      this.len = this.contentArray.length
      if (!this.h || this.len * fontSize > this.h) {
        this.h = this.len * fontSize
      }
      if (this.rowspan <= 1) {
        this.tr.len = Math.max(this.len, this.tr.len)
        this.tr.h = Math.max(this.h, this.tr.h)
      }
    }
  }
  render(w) {
    var _this = this
    var temph = _this.h
    var tempw = w
    const fontSize = this.tr.doctable.font.size
    if (_this.flag & 0x01) {
      _this.tr.doctable.drawLine(_this.point.x, _this.point.y + temph, _this.point.x + tempw, _this.point.y + temph, this.borderSize)
    }
    if (_this.flag & 0x02) {
      _this.tr.doctable.drawLine(_this.point.x + tempw, _this.point.y, _this.point.x + tempw, _this.point.y + temph, this.borderSize)
    }
    if (_this.flag & 0x04) {
      _this.tr.doctable.drawLine(_this.point.x, _this.point.y, _this.point.x, _this.point.y + temph, this.borderSize)
    }
    if (_this.tag && _this.content) {
      _this.tr.doctable.drawImg(_this.content, _this.point.x, _this.point.y, _this.tag)
    }
    if (_this.contentArray) {
      const top = (this.useH - this.contentArray.length * fontSize) >> 1
      for (const i in _this.contentArray) {
        const cc = _this.contentArray[i]
        const c = cc.text
        const left = this.align ? ((this.useW - ((cc.len * fontSize) >> 1)) >> 1) : 0
        _this.tr.doctable.drawText(c, _this.point.x + left, _this.point.y + i * fontSize + top, _this.font)
      }
    }
    _this.point.x += tempw
  }
}

export function BeeDraw(debug) {
  this.doc = new PrintDoc(debug)
  this.doc.debugger = debug || false
  const _this = this
  this.draw = function(params, datasource) {
    _this.doc.width = params.doc.width
    _this.doc.height = params.doc.height
    _this.info = datasource
    if (debug) {
      _this.doc.canvas.width = params.doc.width
      _this.doc.canvas.height = params.doc.height
    }
    const pels = params.els
    for (const i in pels) {
      const f_el = pels[i]
      if (f_el.e === 'table') {
        _this.createTab(f_el)
      }
    }
    return $.extend(_this.doc.render().getCms(), params.doc)
  }
}

BeeDraw.prototype.createTab = function(el) {
  var doctb = new DocTable(this.doc, el.width || this.doc.width, el.lineHeight || 30, el.colwds)
  // function evil(fn) {
  //   const Fn = Function
  //   return new Fn('return ' + fn)()
  // }
  if (el.marge) {
    doctb.setMarge(el.marge)
  }
  if (typeof el.borderSize !== 'undefined') {
    doctb.borderSize = el.borderSize
  }
  if (el.font) {
    $.extend(doctb.font, el.font)
  }
  if (el.source) {
    doctb.data = this[el.source.split('.')[0]][el.source.split('.')[1]]
    // console.log(doctb.data)
    // evil('doctb.data=this.' + el.source)
  }
  for (const j in el.oc) {
    const tr = el.oc[j]
    this.createTr(doctb, tr)
  }
}
BeeDraw.prototype.createTr = function(tb, el) {
  if (el.foreach && tb.data) {
    const list = tb.data
    if (list) {
      delete tb.data
      for (const m in list) {
        el.data = list[m]
        this.createTr(tb, el)
      }
      return
    }
  }
  const p = el.foreach
  const tr = new DocTR(tb)
  for (const j in el.oc) {
    const td = el.oc[j]
    td[p] = el.data
    td.info = this.info
    this.createTd(tr, td)
  }
}

BeeDraw.prototype.createTd = function(tr, el) {
  function evil(fn) {
    const Fn = Function
    return new Fn('return ' + fn)()
  }
  const td = new DocTD(tr)
  td.colspan = el.colspan || 1
  td.rowspan = el.rowspan || 1
  td.content = el.v || ''
  td.align = el.align || 0
  td.tag = el.tag
  if (el.borderLine) {
    td.setBorderLine(el.borderLine)
    td.setBorderSize(1)
  }
  if (el.p) {
    // evil('el.val=el.' + el.p)
    el.val = el[el.p.split('.')[0]][el.p.split('.')[1]]
    td.content = el.val || ''
  }
  if (el.eval) {
    if (typeof el.eval === 'function') {
      td.content = el.eval(el.val || el.info)
    } else {
      td.content = evil(String.format('(' + el.eval + ')({0})', el.val || JSON.stringify(el.info)))
    }
    return
  }
}
